/*
* Copyright (C) 2010-2012 Magnus Skjegstad
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
* 
* The latest version of this library can be downloaded from http://mist-pubsub.googlecode.com
* 
*/
package com.skjegstad.simpleevents;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;

/**
 *
 * @author Magnus Skjegstad
 */
public class SimpleEventPipe {
    private final List<SimpleEventListener> asyncEventListeners = Collections.synchronizedList(new ArrayList());
    private final List<SimpleEventListener> syncEventListeners = Collections.synchronizedList(new ArrayList());
    private ExecutorService executorService;

    public SimpleEventPipe(ExecutorService executorService) {
        this.executorService = executorService;
    }
   
                
    public void listen(SimpleEventListener listener) {                                
        if (listener instanceof SimpleAsyncEventListener)
            asyncEventListeners.add(listener);
        else
            syncEventListeners.add(listener);
    }
    
    public boolean unlisten(SimpleEventListener listener) {        
        if (listener instanceof SimpleAsyncEventListener)
            return asyncEventListeners.remove(listener);
        else
            return syncEventListeners.remove(listener);        
    }
    
    public void trigger(final SimpleEvent event) {
        // Check async first;
        if (asyncEventListeners != null) {
            synchronized(asyncEventListeners) { // as the listeners are spawned in new threads, we can lock here without risking deadlocks
                for (final SimpleEventListener listener : asyncEventListeners) {
                    executorService.submit(new Runnable() {
                        @Override
                        public void run() {
                            listener.receiveEvent(event);
                        }
                    });
                }                    
            }
        }
        
        // Then run synchronous
        if (syncEventListeners != null) {
            for (int i = 0; i < syncEventListeners.size(); i++) {
                try {
                    SimpleEventListener listener = syncEventListeners.get(i);
                    listener.receiveEvent(event);
                } catch (IndexOutOfBoundsException ex ) { // this could happen if an event is deleted while we are in the loop.
                    continue;
                }
            }
        }
    }

}
